package com.task.myThreadPool;

import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

/**
 * @author cxt
 * @date 2022/2/16
 * 线程池
 */
@Slf4j
public class ThreadPool {
    // 任务队列
    private BlockingQueue<Runnable> taskQueue;

    // 线程集合
    private HashSet<Worker> workers = new HashSet();

    // 线程数
    private int coreSize;

    // 线程超时时间
    private long timeout;

    // 时间单位
    private TimeUnit timeUnit;

    // 拒绝策略
    private RejectPolicy<Runnable> rejectPolicy;

    // 执行任务
    public void executor(Runnable task) {
        // 当前任务没有超过 corSize 时候，将任务放在队列中
        if (workers.size() < coreSize) {
            Worker worker = new Worker(task);  // 这里就是创建了一个线程
            log.debug("线程创建完成……{}，{}", worker, task);
            workers.add(worker);
            worker.start();
        } else {
            // 线程池中核心线程数满了之后加入队列中
            log.debug("任务加入队列{}", task);
//            taskQueue.put(task);
            // 如果队列已满的话，这里有几种情况
            // 1、死等
            // 2、超时放弃
            // 3、直接放弃添加
            // 4、调用者抛出异常
            // 5、调用者自己执行当前任务
            // 策略模式
            taskQueue.tryPut(rejectPolicy, task);
        }
    }

    public ThreadPool(int coreSize, long timeout, TimeUnit timeUnit, int queueCapcity, RejectPolicy<Runnable> rejectPolicy) {
        this.coreSize = coreSize;
        this.timeout = timeout;
        this.timeUnit = timeUnit;
        this.rejectPolicy = rejectPolicy;
        this.taskQueue = new BlockingQueue<>(queueCapcity);
    }

    // 包装的线程
    class Worker extends Thread {
        private Runnable task;

        public Worker(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            // 执行任务
            // 1、task不为空时，执行task
            // 2、task为空，执行队列中的任务
            // todo 线程会卡在这，因为 taskQueue.take() 会一直获取任务
            while (task != null || (task = taskQueue.take()) != null) {
                try {
                    log.debug("正在执行……队列剩余：{}", taskQueue.size());
                    task.run();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    task = null;
                }
            }
            synchronized (workers) {
                log.debug("移除线程……{}", this);
                workers.remove(this);
            }
        }
    }
}
